package com.jhws.business.property.service;

import com.alibaba.fastjson.JSON;
import com.jhws.business.comm.bo.Room;
import com.jhws.business.comm.bo.RoomType;
import com.jhws.business.comm.bo.TblBuildingDimBo;
import com.jhws.business.comm.service.ITblBuildingDimService;
import com.jhws.business.comm.service.RoomService;
import com.jhws.business.comm.service.RoomTypeService;
import com.jhws.business.owner.bo.TblOwnerDimBo;
import com.jhws.business.owner.service.ITblOwnerDimService;
import com.jhws.business.property.bo.*;
import com.jhws.core.dataUpdate.bo.DataUpdateConstant;
import com.jhws.core.dataUpdate.service.DataUpdateService;
import com.jhws.core.exception.BizException;
import com.jhws.util.DateUtil;
import com.jhws.util.GetId;
import com.jhws.util.StringUtils;
import com.jhws.util.i.Callback;
import org.apache.commons.collections.MapUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.ParseException;
import java.util.*;

@Service
public class PropertyFeeService {
    @Resource
    private com.jhws.core.db.BaseDao BaseDao;
    @Resource
    private ITblBuildingDimService buildingDimService;
    @Resource
    private RoomService roomService;
    @Resource
    private RoomTypeService roomTypeService;
    @Resource
    private PropertyFeeFormulaService propertyFeeFormulaService;
    @Resource
    private ITblOwnerDimService ownerDimService;
    @Resource
    private DataUpdateService dataUpdateService;

    /**
     * 保存物业缴费
     *
     * @param propertyFeeInfo 物业缴费信息
     */
    public void savePropertyFee(PropertyFeeInfo propertyFeeInfo) throws Exception {
        if (StringUtils.isEmpty(propertyFeeInfo.getId())) {
            propertyFeeInfo.setId(GetId.randomID());
        }
        BaseDao.saveOrUpdate(propertyFeeInfo);
    }

    /**
     * 根据小区保存最新的账单
     */
    public void savePropertyFeeByCommCode(String commCode) throws Exception {
        String where = "where is_enable='1' and comm_code='" + commCode + "'";
        List<PropertyFeeFormula> propertyFeeFormulas = propertyFeeFormulaService.queryPropertyFeeFormulaWhere(where);
        if (propertyFeeFormulas == null || propertyFeeFormulas.size() != 1) {
            throw new BizException("-1", "", "没有定义公式！");
        }
        List<RoomType> roomTypes = roomTypeService.queryRoomTypes("where comm_code='" + commCode + "'");
        if (roomTypes == null || roomTypes.size() == 0) {
            throw new BizException("-1", "", "没有户型，请创建户型后，分配到相应的房间在生成！");
        }
        PropertyFeeFormula propertyFeeFormula = propertyFeeFormulas.get(0);
        if (PropertyConstant.AREA_TYPE.equals(propertyFeeFormula.getType())) {
            getRoomInfo(commCode, roomTypes, new Callback<Object>() {
                @Override
                public void callback(Object... o) throws Exception {
                    Room room = (Room) o[0];
                    RoomType roomType = (RoomType) o[1];
                    PropertyFeeInfo propertyFeeInfo = queryPropertyFee(room.getId());
                    if (propertyFeeInfo == null || propertyFeeInfo.getLastBillDate() == null) {
                        if (propertyFeeInfo == null) {
                            propertyFeeInfo = new PropertyFeeInfo();
                        }
                        // 如果上次缴费账单时间为null，默认需要交一个缴费周期的费用
                        propertyFeeInfo.setLastBillDate(DateUtil.getDateDay(DateUtil.getDateByMonth(new Date(), -propertyFeeFormula.getChargeCycle()), propertyFeeFormula.getBillDay(), DateUtil.DATE_FORMAT));
                    }
                    int LastBillDay = DateUtil.getDateByField(DateUtil.stringDate(propertyFeeInfo.getLastBillDate(), DateUtil.DATE_FORMAT), Calendar.DAY_OF_MONTH);
                    if (propertyFeeFormula.getBillDay() != LastBillDay) { //如果账单日有修改，重置一下
                        propertyFeeInfo.setLastBillDate(DateUtil.getDateDay(DateUtil.stringDate(propertyFeeInfo.getLastBillDate(), DateUtil.DATE_FORMAT), propertyFeeFormula.getBillDay(), DateUtil.DATE_FORMAT));
                    }
                    int months = getMonths(propertyFeeInfo.getLastBillDate(), propertyFeeFormula.getChargeCycle(), propertyFeeFormula.getBillDay());
                    if (months > 0) {
                        propertyFeeInfo.setCurrentBillDate(DateUtil.getDateByMonth(DateUtil.stringDate(propertyFeeInfo.getLastBillDate(), "yyyy-MM-dd"), months, DateUtil.DATE_FORMAT));
                        propertyFeeInfo.setMonths(months);
                        propertyFeeInfo.setId(room.getId());
                        propertyFeeInfo.setCommCode(room.getCommCode());
                        propertyFeeInfo.setIsPay(0);
                        propertyFeeInfo.setFee(String.valueOf(roomType.getFloorArea() * Float.valueOf(propertyFeeFormula.getCustomContent()) * months));
                        savePropertyFee(propertyFeeInfo);
                    }
                }
            });
        } else if (PropertyConstant.FLOOR_AREA_TYPE.equals(propertyFeeFormula.getType())) {
            getRoomInfo(commCode, roomTypes, new Callback<Object>() {
                @Override
                public void callback(Object... o) throws Exception {
                    Room room = (Room) o[0];
                    RoomType roomType = (RoomType) o[1];
                    PropertyFeeInfo propertyFeeInfo = queryPropertyFee(room.getId());
                    if (propertyFeeInfo == null || propertyFeeInfo.getLastBillDate() == null) {
                        if (propertyFeeInfo == null) {
                            propertyFeeInfo = new PropertyFeeInfo();
                        }
                        // 如果上次缴费账单时间为null，默认需要交一个缴费周期的费用
                        propertyFeeInfo.setLastBillDate(DateUtil.getDateDay(DateUtil.getDateByMonth(new Date(), -propertyFeeFormula.getChargeCycle()), propertyFeeFormula.getBillDay(), DateUtil.DATE_FORMAT));
                    }
                    //得到楼层相关的费率
                    List<PropertyFeeCustomContent> customContents = JSON.parseArray(propertyFeeFormula.getCustomContent(), PropertyFeeCustomContent.class);
                    int floor = Integer.valueOf(room.getFloorCode());
                    for (PropertyFeeCustomContent customContent : customContents) {
                        if (floor >= customContent.getStartFloor() && floor <= customContent.getEndFloor()) {
                            int LastBillDay = DateUtil.getDateByField(DateUtil.stringDate(propertyFeeInfo.getLastBillDate(), DateUtil.DATE_FORMAT), Calendar.DAY_OF_MONTH);
                            if (propertyFeeFormula.getBillDay() != LastBillDay) { //如果账单日有修改，重置一下
                                propertyFeeInfo.setLastBillDate(DateUtil.getDateDay(DateUtil.stringDate(propertyFeeInfo.getLastBillDate(), DateUtil.DATE_FORMAT), propertyFeeFormula.getBillDay(), DateUtil.DATE_FORMAT));
                            }
                            int months = getMonths(propertyFeeInfo.getLastBillDate(), propertyFeeFormula.getChargeCycle(), propertyFeeFormula.getBillDay());
                            if (months > 0) {
                                propertyFeeInfo.setCurrentBillDate(DateUtil.getDateByMonth(DateUtil.stringDate(propertyFeeInfo.getLastBillDate(), "yyyy-MM-dd"), months, DateUtil.DATE_FORMAT));
                                propertyFeeInfo.setMonths(months);
                                propertyFeeInfo.setId(room.getId());
                                propertyFeeInfo.setCommCode(room.getCommCode());
                                propertyFeeInfo.setIsPay(0);
                                propertyFeeInfo.setFee(String.valueOf(roomType.getFloorArea() * customContent.getRate() * months));
                                savePropertyFee(propertyFeeInfo);
                            }
                            break;
                        }
                    }
                }
            });
        } else {
            throw new BizException("-1", "", "该小区没有可创建的物业缴费信息！");
        }
    }

    /**
     * 更新状态
     */
    public void saveState(String id, int isPay, String lastBillDate) {
        String hql = "UPDATE PropertyFeeInfo SET isPay='" + isPay + "' ";
        if (StringUtils.isNotEmpty(lastBillDate)) {
            hql += ", lastBillDate='" + lastBillDate + "' ";
        }
        hql += "WHERE id='" + id + "'";
        BaseDao.executeHql(hql);
    }

    /**
     * 根据业主ID查询物业缴费信息
     *
     * @return
     */
    public PropertyFeeBo queryPropertyFeeByOwnerCode(String ownerCode, Integer isPay) {
        TblOwnerDimBo ownerDimBo = ownerDimService.findTblOwnerDimById(ownerCode);
        String hql = "select new com.jhws.business.property.bo.PropertyFeeBo(pfi.id, pfi.fee, pfi.isPay, pfi.months, pfi.currentBillDate," +
                " pfi.lastBillDate, rt.floorArea, rt.roomTypeName , rt.roomTypeUrl) " +
                "from PropertyFeeInfo as pfi, Room as r, RoomType as rt where pfi.id=r.id and r.roomTypeId=rt.id and r.id='" + ownerDimBo.getRoomInfoNum() + "'";
        if (isPay != null) {
            hql += "  and isPay='" + isPay + "'";
        }
        List<PropertyFeeBo> propertyFeeBos = BaseDao.findList(hql);
        if (propertyFeeBos != null && propertyFeeBos.size() > 0) return propertyFeeBos.get(0);
        return null;
    }

    /**
     * 分页查询物业缴费信息
     *
     * @param param Map
     * @return 物业缴费信息列表
     */
    @SuppressWarnings("unchecked")
    public Map queryPropertyFeePage(Map param) throws Exception {
        String hql = "select new com.jhws.business.property.bo.PropertyFeeBo(pfi.id, pfi.fee, pfi.isPay, pfi.lastBillDate," +
                "r.commCode, r.buildingCode, r.unitCode, r.floorCode, r.roomCode, r.roomTypeId) " +
                "from PropertyFeeInfo as pfi, Room as r where pfi.id=r.id ";
        String commCode = MapUtils.getString(param, "commCode", "");
        if (StringUtils.isNotEmpty(commCode)) {
            hql += " and r.commCode = '" + commCode + "' ";
        }
        String buildingCode = MapUtils.getString(param, "buildingCode", "");
        if (StringUtils.isNotEmpty(buildingCode)) {
            hql += " and r.buildingCode = '" + buildingCode + "'";
        }
        String unitCode = MapUtils.getString(param, "unitCode", "");
        if (StringUtils.isNotEmpty(unitCode)) {
            hql += " and r.unitCode = '" + unitCode + "'";
        }
        String floorCode = MapUtils.getString(param, "floorCode", "");
        if (StringUtils.isNotEmpty(floorCode)) {
            hql += " and r.floorCode = '" + floorCode + "'";
        }
        String roomCode = MapUtils.getString(param, "roomCode", "");
        if (StringUtils.isNotEmpty(roomCode)) {
            hql += " and r.roomCode = '" + roomCode + "' ";
        }
        Map map = BaseDao.queryPage(hql);

        List<PropertyFeeBo> propertyFeeBos = (List<PropertyFeeBo>) map.get("list");
        for (PropertyFeeBo propertyFeeBo : propertyFeeBos) {
            String where = "where comm_code = '" + propertyFeeBo.getCommCode() + "' and area_name = CAST(" + propertyFeeBo.getBuildingCode() + " as integer) and building_name = CAST(" + propertyFeeBo.getUnitCode() + " as integer) ";
            List<TblBuildingDimBo> list = buildingDimService.findTblBuildingDimByWhere(where);
            if (list != null && list.size() > 0) {
                propertyFeeBo.setCommName(list.get(0).getCommName());
                propertyFeeBo.setBuildingAliasName(list.get(0).getAreaAliasName());
                propertyFeeBo.setUnitAliasName(list.get(0).getBuildingAliasName());
            }
        }
        return map;
    }

    public List<PropertyFeeBo> getPropertyFeesForExport(String commCode) {
        String hql = "select new com.jhws.business.property.bo.PropertyFeeBo(pfi.fee, " +
                "pfi.isPay, " +
                "pfi.months," +
                "pfi.lastBillDate, " +
                "pfi.currentBillDate, " +
                "r.commCode, " +
                "r.buildingCode, " +
                "r.unitCode, " +
                "r.floorCode, " +
                "r.roomCode) from PropertyFeeInfo as pfi, Room as r where pfi.id=r.id and r.commCode='" + commCode + "'";
        return BaseDao.findList(hql);
    }

    /**
     * 物业缴费信息
     *
     * @param id 物业缴费ID
     */
    public PropertyFeeInfo queryPropertyFee(String id) {
        return BaseDao.get(PropertyFeeInfo.class, id);
    }

    /**
     * 条件物业缴费信息
     *
     * @param where 条件
     * @return
     */
    public List<PropertyFeeInfo> queryPropertyFeeWhere(String where) {
        return BaseDao.findList("from PropertyFeeInfo " + where);
    }

    /**
     * 催缴物业费
     */
    @Async
    public void callPropertyFee(String commCode) throws Exception {
        String hql = "select new map(o.ownerMob as ownerMob, o.commName as commName) from PropertyFeeInfo as pfi, TblOwnerDimBo as o where pfi.id=o.roomInfoNum and pfi.commCode='" + commCode + "' and pfi.isPay='0'";
        List<Map<String, String>> mapList = BaseDao.findList(hql);
        for (Map<String, String> map : mapList) {
            dataUpdateService.pushAndUpdate(new Date().getTime(), PropertyFeeDataUpdate.PROPERTY_FEE, map.get("ownerMob"), true, true, "【" + map.get("commName") + "】你有新的物业缴费账单", "物业缴费账单已经生成，请注意查看。");
        }
    }


    /**
     * 获取需要缴费的月数
     *
     * @return 月数
     */
    private int getMonths(String lastBillDate, int chargeCycle, int billDay) throws ParseException {
        int day = DateUtil.getDateByField(Calendar.DAY_OF_MONTH);
        int months = 0;
        if (day >= billDay) { //只要当前天数大于等于账单日，就以当前月计算
            months = DateUtil.monthsBetween(lastBillDate, DateUtil.getTimeNowFmtSec(DateUtil.DATE_FORMAT));
        } else { // 如果小于，就以上一个月计算
            months = DateUtil.monthsBetween(lastBillDate, DateUtil.getDateByMonth(-1, DateUtil.DATE_FORMAT));
        }
        int mul = months / chargeCycle; //是否大于缴费周期，大于才计算缴费月
        if (mul >= 1) {
            return mul * chargeCycle; //缴费月
        } else {
            return 0;
        }
    }

    /**
     * 按小区获取房间信息
     *
     * @param commCode
     * @param callback
     */
    private void getRoomInfo(String commCode, List<RoomType> roomTypes, Callback<Object> callback) throws Exception {
        List<Room> rooms = roomService.queryRooms("where comm_code='" + commCode + "'");
        for (Room room : rooms) {
            for (RoomType roomType : roomTypes) {
                if (Objects.equals(roomType.getId(), room.getRoomTypeId())) {
                    callback.callback(room, roomType);
                }
            }
        }
    }

    /**
     * 催缴物业费
     *
     * @param roomInfo
     * @throws Exception
     */
    private void push(String roomInfo) throws Exception {
        List<TblOwnerDimBo> ownerDimBos = ownerDimService.findTblOwnerDimByWhere("where room_info_num = '" + roomInfo + "'");
        if (ownerDimBos != null && ownerDimBos.size() > 0) {
            for (TblOwnerDimBo ownerDimBo : ownerDimBos) {
                dataUpdateService.push(PropertyFeeDataUpdate.PROPERTY_FEE, ownerDimBo.getOwnerMob(), DataUpdateConstant.PUSH_TYPE_ACCOUNT, true, "物业缴费", "物业缴费账单已经生成，请注意查看。");
            }
        }
    }
}
